/* ----------------------------------------------------------------------------
* File: utils.h
*
* Desc: Common SKype utils
*
* Created: 07/06/2011, by Alexey Korshunov
* ---------------------------------------------------------------------------- */
#ifndef _UTILS_H_
#define _UTILS_H_

#include <windows.h>
#include <queue>

void MyOutputDebugString(const char *str, ...);

namespace Common
{
	namespace Utils
	{
		class LockGuard
		{
		private:
			LockGuard(const LockGuard&);
			LockGuard& operator=(const LockGuard&);
		public:
			explicit LockGuard(CRITICAL_SECTION& csLock)
				: m_csLock(&csLock)
			{
				EnterCriticalSection(m_csLock);
			}

			~LockGuard()
			{
				LeaveCriticalSection(m_csLock);
			}

		private:
			LPCRITICAL_SECTION m_csLock;
		};
	}

	namespace Utils
	{
		struct ConcurrentQueueParams
		{
			ConcurrentQueueParams()
				: useEventNotify(false)
				, PushEvent(NULL)
				, PopEvent(NULL)
			{
			}

			bool useEventNotify;
			HANDLE PushEvent;
			HANDLE PopEvent;
		};

		template <class T>
		class ConcurrentQueue
		{
		public:
			explicit ConcurrentQueue(const ConcurrentQueueParams& params)
			{
				InitializeCriticalSection(&m_csLock);
				m_Params = params;
				if (m_Params.PushEvent == NULL ||
					m_Params.PopEvent == NULL)
					m_Params.useEventNotify = false;
			}

			~ConcurrentQueue()
			{
				DeleteCriticalSection(&m_csLock);
			}

			void push(const T& data)
			{
				LockGuard guard(m_csLock);
				m_queue.push(data);
				if (m_Params.useEventNotify)
					::SetEvent(m_Params.PushEvent);
			}

			void pop()
			{
				LockGuard guard(m_csLock);
				m_queue.pop();
				if (m_Params.useEventNotify)
					::SetEvent(m_Params.PopEvent);
			}

			T& front()
			{
				LockGuard guard(m_csLock);
				return m_queue.front();
			}

			T const& front() const
			{
				LockGuard guard(m_csLock);
				return m_queue.front();
			}

			T& back()
			{
				LockGuard guard(m_csLock);
				return m_queue.back();
			}

			T const& back() const
			{
				LockGuard guard(m_csLock);
				return m_queue.back();
			}

			size_t size()
			{
				LockGuard guard(m_csLock);
				return m_queue.size();
			}

			void clear()
			{
				LockGuard guard(m_csLock);
				while(m_queue.size())
					m_queue.pop();
			}

			HANDLE GetPushEvent() const
			{
				return m_Params.PushEvent;
			}

			HANDLE GetPopEvent() const
			{
				return m_Params.PopEvent;
			}

		private:
			std::queue<T> m_queue;
			CRITICAL_SECTION m_csLock;
			ConcurrentQueueParams m_Params;
		};
	}
}

#endif // _UTILS_H_